package com.qlogic.commons.platform.impls.lucene.indexer;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.Term;
import org.apache.lucene.store.Directory;

import com.qlogic.commons.exceptions.BaseException;
import com.qlogic.commons.kernel.Kernel;
import com.qlogic.commons.platform.ServiceExecutionException;
import com.qlogic.commons.platform.impls.lucene.handler.ContentHandler;
import com.qlogic.commons.platform.impls.lucene.model.DocumentWrapper;
import com.qlogic.commons.platform.impls.lucene.model.FieldWrapper;

public class LuceneUtils {
	
	public static void addDocuments (Map documents, String indexer, IndexWriter indexWriter, IndexReader indexReader) throws ServiceExecutionException {
		if (documents.isEmpty ()) {
			return;
		}
		boolean close = false;
		if (indexWriter == null) {
			close = true;
			try {
				indexWriter = 
					(IndexWriter)Kernel.getResource ("contentService/indexers/" + indexer).getValue ();
			} catch (BaseException e) {
				throw new ServiceExecutionException (e);
			} 
		}
		Set contentIds = documents.keySet ();
		Iterator iterator = contentIds.iterator ();
		while (iterator.hasNext ()) {
			String id = (String)iterator.next ();
			DocumentWrapper documentWrapper = (DocumentWrapper)documents.get (id);
			if (documentWrapper != null) {
				try {
					indexWriter.addDocument (toDocument (documentWrapper));
				} catch (IOException ioex) {
					throw new ServiceExecutionException (ioex);
				} 
			}
		}
		if (close) {
			try {
				indexWriter.optimize ();
				indexWriter.close();
			} catch (IOException ioex) {
				throw new ServiceExecutionException (ioex);
			}
		}
		
	}

	public static void delete (String fieldName, String fieldValue, String indexer, IndexWriter indexWriter, IndexReader indexReader) throws ServiceExecutionException {
		try {
			if (indexReader == null) {
				indexReader = 
					IndexReader.open ((Directory)Kernel.getResource ("contentService/indexers/" + indexer + "/directory").getValue ());
			}
			Term term = new Term (fieldName, fieldValue);
			indexReader.deleteDocuments (term);
			indexReader.close ();
		} catch (BaseException e) {
			throw new ServiceExecutionException (e);
		} catch (IOException ioex) {
			throw new ServiceExecutionException (ioex);
		} 
	}

	public static void delete (String contentId, String indexer, IndexWriter indexWriter, IndexReader indexReader) throws ServiceExecutionException {
		try {
			if (indexReader == null) {
				indexReader = 
					IndexReader.open ((Directory)Kernel.getResource ("contentService/indexers/" + indexer + "/directory").getValue ());
			}
			Term term = new Term (LuceneIndexerService.CONTENT_ID, contentId);
			indexReader.deleteDocuments (term);
			indexReader.close ();
		} catch (BaseException e) {
			throw new ServiceExecutionException (e);
		} catch (IOException ioex) {
			throw new ServiceExecutionException (ioex);
		} 
	}
	
	public static Document toDocument (DocumentWrapper documentWrapper) throws ServiceExecutionException {
		if (documentWrapper == null) {
			return null;
		}
		Document document = new Document ();
		Map fields = documentWrapper.getFields ();
		Iterator fieldNames = fields.keySet().iterator ();
		while (fieldNames.hasNext ()) {
			String fieldName = (String)fieldNames.next ();
			Field field = toField (documentWrapper.getId (), (FieldWrapper)fields.get (fieldName));
			if (field != null) {
				document.add (field);
			}
		}
		return document;
	}
	
	public static DocumentWrapper toDocumentWrapper (Document document, String encoding) throws UnsupportedEncodingException {
		DocumentWrapper documentWrapper = new DocumentWrapper ();
		documentWrapper.setId(document.getField(LuceneIndexerService.CONTENT_ID).stringValue ());
		Enumeration fields = document.fields();
		while (fields.hasMoreElements()) {
			Field field = (Field) fields.nextElement();
			if (!field.name().equals(LuceneIndexerService.CONTENT_ID)) {
				FieldWrapper fieldWrapper = 
					new FieldWrapper (field.name(), field.binaryValue (), null, true, true, encoding);
				documentWrapper.addField(fieldWrapper);
			}
		}
		
		return documentWrapper;
	}
	
	public static Field toField (String contentId, FieldWrapper fieldWrapper) throws ServiceExecutionException {
		if (fieldWrapper == null) {
			return null;
		}
		String parsedValue = null;
		if (fieldWrapper.getHandler () != null) {
			try {
				ContentHandler documentHandler = 
					(ContentHandler)Kernel.getResource ("contentService/handlers/" + 
							fieldWrapper.getHandler ()).getValue ();
				parsedValue = documentHandler.getText (
						new ByteArrayInputStream (fieldWrapper.getValue ()), "UTF-8");
			} catch (BaseException e) {
				throw new ServiceExecutionException (e);
			} 
		} else {
			try {
				parsedValue = new String (fieldWrapper.getValue (), "ISO-8859-1");
			} catch (UnsupportedEncodingException e) {
				throw new ServiceExecutionException (e);
			}
		}
		if (parsedValue == null) {
			throw new ServiceExecutionException ("Can not add null value for field [" + 
					contentId + " --> " + fieldWrapper.getName () + "]");
		}
		Field field = new Field (fieldWrapper.getName (), parsedValue, 
				fieldWrapper.isStore () ? Field.Store.YES : Field.Store.NO, 
						fieldWrapper.isTokenized () ? Field.Index.TOKENIZED : Field.Index.UN_TOKENIZED);
		return field;
	}

}
